﻿using System;
using System.Drawing;
using System.Globalization;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace JN.Utility
{
    [Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
    public struct PointD
    {
        public static readonly PointD Empty;
        private double _x;
        private double _y;

        [Browsable(false)]
        public bool IsEmpty
        {
            get { return ((this._x == 0) && (this._y == 0)); }
        }

        public double X
        {
            get { return this._x; }
            set { this._x = value; }
        }

        public double Y
        {
            get { return this._y; }
            set { this._y = value; }
        }

        public PointD(double x, double y)
        {
            this._x = x;
            this._y = y;
        }

        public void Offset( double xOffset, double yOffset)
        {
            PointD p = PointD.Empty;
            _x = (double)(_x + xOffset);
            _y = (double)(_y + yOffset);
        }

        public void Rotation(double angle)
        {
            if (angle == 0.0)
            {
                return;
            }
            double distance = Math.Sqrt((_x * _x) + (_y * _y));
            double d = Math.Atan2( _y , _x) + angle;
 
            _x = (float)(distance * Math.Cos(d)); 
            _y = (float)(distance * Math.Sin(d)); 
        }

        public void Mirror(  bool isMirrorX, bool isMirrorY)
        {
            _x = (isMirrorX ? - _x: _x);
            _y = (isMirrorY ? - _y : _y);
        }

        public void Scale( double xScale, double yScale)
        {
            _x = (float)(_x * xScale);
            _y = (float)(_y * yScale); 
        }

        public static PointD operator +(PointD pt, Size sz)
        {
            return Add(pt, sz);
        }

        public static PointD operator -(PointD pt, Size sz)
        {
            return Subtract(pt, sz);
        }

        public static PointD operator +(PointD pt, SizeF sz)
        {
            return Add(pt, sz);
        }

        public static PointD operator -(PointD pt, SizeF sz)
        {
            return Subtract(pt, sz);
        }

        public static PointD operator +(PointD pt, SizeD sz)
        {
            return Add(pt, sz);
        }

        public static PointD operator -(PointD pt, SizeD sz)
        {
            return Subtract(pt, sz);
        }

        public static bool operator ==(PointD left, PointD right)
        {
            return ((left.X == right.X) && (left.Y == right.Y));
        }

        public static bool operator !=(PointD left, PointD right)
        {
            return !(left == right);
        }

        public static PointD Add(PointD pt, Size sz)
        {
            return new PointD(pt.X + sz.Width, pt.Y + sz.Height);
        }

        public static PointD Subtract(PointD pt, Size sz)
        {
            return new PointD(pt.X - sz.Width, pt.Y - sz.Height);
        }

        public static PointD Add(PointD pt, SizeF sz)
        {
            return new PointD(pt.X + sz.Width, pt.Y + sz.Height);
        }

        public static PointD Subtract(PointD pt, SizeF sz)
        {
            return new PointD(pt.X - sz.Width, pt.Y - sz.Height);
        }

        public static PointD Add(PointD pt, SizeD sz)
        {
            return new PointD(pt.X + sz.Width, pt.Y + sz.Height);
        }

        public static PointD Subtract(PointD pt, SizeD sz)
        {
            return new PointD(pt.X - sz.Width, pt.Y - sz.Height);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is PointD))
            {
                return false;
            }
            PointD tf = (PointD)obj;
            return (((tf.X == this.X) && (tf.Y == this.Y)) && tf.GetType().Equals(base.GetType()));
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return string.Format(CultureInfo.CurrentCulture, "{{X={0}, Y={1}}}", new object[] { this._x, this._y });
        }

        static PointD()
        {
            Empty = new PointD();
        }

        public static implicit operator Point(PointD point)
        {
            return new Point(Convert.ToInt32(point.X), Convert.ToInt32(point.Y));
        }

        public static implicit operator PointF(PointD point)
        {
            return new PointF(Convert.ToSingle(point.X), Convert.ToSingle(point.Y));
        }

        public static implicit operator PointD(PointF point)
        {
            return new PointD(point.X, point.Y);
        }

        public static implicit operator PointD(Point point)
        {
            return new PointD(point.X, point.Y);
        }

        public static PointD operator +(PointD p1, PointD p2)
        {
            return new PointD(p1.X + p2.X ,p1.Y + p2.Y); 
        }

        public static PointD operator -(PointD p1, PointD p2)
        {
            return new PointD(p1.X - p2.X, p1.Y - p2.Y);
        }

        public static PointD operator *(PointD p, double value)
        {
            return new PointD(p.X * value, p.Y * value);
        }

        public static PointD operator *(double value, PointD p)
        {
            return p * value;
        }

        public static PointD operator /(PointD p, double value)
        {
            if (value != 0)
            {
                return new PointD(p.X / value, p.Y / value); 
            }
            return p;
        }

    }
}
